from storageEngine import IStorageEngine
from btreeFactory import BtreeFactory

class RawBtreeStorageErrorCode:
    TableNotExist = -100
    DuplicatedPrimaryKey = -101
    KeyNotExist = -102

class RawBtreeStorage(IStorageEngine):
    class IRawBtreeDao(IStorageEngine.IDao):
        def getName(self):
            return self.__table

        def toPojo(self, obj, **kwargs):
            pass

        def getKey(self):
            pass
        def getValue(self):
            pass

    def __init__(self, fileName):
        self.__btrees = {}

    def hasBtree(self, name):
        return name in self.__btrees
    def __getBtree(self, name):
        return self.hasBtree(name) and self.__btrees[name] or None

    def close(self):
        for bt in self.__btrees:
            bt.close()

    def create(self, obj, **kwargs):
        name = obj.getName()
        if not self.hasBtree(name):
            self.__btrees[name] = BtreeFactory(name)
        return 0

    def drop(self, obj, **kwargs):
        btree = self.__getBtree(obj.getName())
        if btree is not None:
            return btree.clear()
        return 0

    def insert(self, obj, **kwargs):
        btree = self.__getBtree(obj.getName())
        key = obj.getKey()
        if btree is not None:
            return btree.insert(key, obj.getValue()) # errorCode: DuplicatedPrimaryKey, KeyNotExist
        return RawBtreeStorageErrorCode.TableNotExist

    def delete(self, obj, **kwargs):
        btree = self.__getBtree(obj.getName())
        key = obj.getKey()
        if btree is not None:
            return btree.delete(key)   
        return RawBtreeStorageErrorCode.TableNotExist

    def query(self, obj, **kwargs):
        btree = self.__getBtree(obj.getName())
        key = obj.getKey()
        if btree is not None:
            value = btree.find(key)
            return value is not None and obj.toPojo(value) or None
        else:
            return RawBtreeStorageErrorCode.TableNotExist

    def update(self, obj, **kwargs):
        cursor = self.query(obj, cmd="pk");
        if cursor is not None:
            self.delete(obj, **kwargs)
        return self.insert(obj, **kwargs)
#end class




##### Test code for RawBtreeStorage

import json
from order import MockOrder
class MockOrderRBao:
    def __init__(self, order):
        self.__order = order
        self.__table = "order"

    def getName(self):
        return self.__table

    def toPojo(self, obj, **kwargs):
        if isinstance(obj, str):
            jsobj = json.loads(obj)
            return MockOrder(**jsobj)
        return None

    def getKey(self):
        return self.__order.orderId
    def getValue(self):
        return "{orderId:%d,orderNo:%s,price:%f}"% (self.__order.orderId, self.__order.orderNo, self.__order.price)


import unittest 

class TestRawBtreeStorage(unittest.TestCase):
    def testRawBtreeDao(self):
        order = MockOrder(orderId=1, orderNo="000001", price=257.8)
        rbao = MockOrderRBao(order)
        self.assertEqual(rbao.getKey(), 1)
        self.assertEqual("{orderId:1,orderNo:000001,price:257.800000}", rbao.getValue())

    def testUse(self):
        rbs = RawBtreeStorage("test.raw")
        rbao = MockOrderRBao(MockOrder(orderId=1, orderNo="000001", price=257.8))
        self.assertEqual(0, rbs.create(rbao))
        self.assertEqual(0, rbs.drop(rbao))
        self.assertEqual(0, rbs.insert(rbao))
        self.assertEqual(0, rbs.delete(rbao))
        self.assertEqual(0, rbs.update(rbao))
        pojo = rbs.query(rbao)
        print(type(pojo), str(pojo))

if __name__ == "__main__":
    suite = unittest.TestSuite([
          unittest.TestLoader().loadTestsFromTestCase(TestRawBtreeStorage),
              ])
    unittest.TextTestRunner(verbosity=2).run(suite)
